
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                              vsprintf.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

/*======================================================================*
                                i2a
 *======================================================================*/
PRIVATE char *i2a(int val, int base, char **ps)
{
    int m = val % base;
    int q = val / base;
    if (q)
    {
        i2a(q, base, ps);
    }
    *(*ps)++ = (m < 10) ? (m + '0') : (m - 10 + 'A');

    return *ps;
}

/*======================================================================*
                                vsprintf
 *======================================================================*/
/*
 *  为更好地理解此函数的原理，可参考 printf 的注释部分。
 */
PUBLIC int vsprintf(char *buf, const char *fmt, va_list args)
{
    char *p;

    va_list p_next_arg = args;
    int m;

    char inner_buf[STR_DEFAULT_LEN];
    char cs;
    int align_nr;

    for (p = buf; *fmt; fmt++)
    {
        if (*fmt != '%')
        {
            *p++ = *fmt;
            continue;
        }
        else
        { /* a format string begins */
            align_nr = 0;
        }

        fmt++;

        if (*fmt == '%')
        {
            *p++ = *fmt;
            continue;
        }
        else if (*fmt == '0')
        {
            cs = '0';
            fmt++;
        }
        else
        {
            cs = ' ';
        }
        while (((unsigned char)(*fmt) >= '0') && ((unsigned char)(*fmt) <= '9'))
        {
            align_nr *= 10;
            align_nr += *fmt - '0';
            fmt++;
        }

        char *q = inner_buf;
        memset(q, 0, sizeof(inner_buf));

        switch (*fmt)
        {
        case 'c':
            *q++ = *((char *)p_next_arg);
            p_next_arg += 4;
            break;
        case 'x':
            m = *((int *)p_next_arg);
            i2a(m, 16, &q);
            p_next_arg += 4;
            break;
        case 'd':
            m = *((int *)p_next_arg);
            if (m < 0)
            {
                m = m * (-1);
                *q++ = '-';
            }
            i2a(m, 10, &q);
            p_next_arg += 4;
            break;
        case 's':
            strcpy(q, (*((char **)p_next_arg)));
            q += strlen(*((char **)p_next_arg));
            p_next_arg += 4;
            break;
        default:
            break;
        }

        int k;
        for (k = 0; k < ((align_nr > strlen(inner_buf)) ? (align_nr - strlen(inner_buf)) : 0); k++)
        {
            *p++ = cs;
        }
        q = inner_buf;
        while (*q)
        {
            *p++ = *q++;
        }
    }

    *p = 0;

    return (p - buf);
}

/*======================================================================*
                                 sprintf
 *======================================================================*/
int sprintf(char *buf, const char *fmt, ...)
{
    va_list arg = (va_list)((char *)(&fmt) + 4); /* 4 是参数 fmt 所占堆栈中的大小 */
    return vsprintf(buf, fmt, arg);
}
